use anyhow::bail;
use axum::{extract::State, Json, response::IntoResponse};
use axum::http::StatusCode;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgDatabaseError;
use tracing::{debug, error, info};
use crate::{AppError, AppState, ErrorOutput, models::CreateUser, User};
use crate::AppError::SqlxError;

#[derive(Debug, Serialize)]
pub struct Token {
    pub token: String,
}

pub(crate) async fn signin_handler(State(state): State<AppState>,
                                   Json(input): Json<CreateUser>) ->
                                   anyhow::Result<impl IntoResponse, AppError> {
    debug!("signin_handler enter");

    let option = User::verify(&input.email, &input.password, &state.pool).await?;
    if let Some(u) = option {
        error!("email already exists: {}", u.email);
        let body = Json(ErrorOutput::new(format!("Invalid email or password: {}", u.email)));
        Ok((StatusCode::FORBIDDEN, body).into_response())
    } else {
        let user
            = User::create(&input.email, &input.fullname, &input.password, &state.pool).await?;

        let token = state.ek.encode(user.clone())?;

        let ret: Json<Token> = Json(Token { token });

        Ok((StatusCode::CREATED, ret).into_response())
    }
}

pub(crate) async fn signup_handler(
    State(state): State<AppState>,
    Json(input): Json<CreateUser>,
) -> Result<impl IntoResponse, AppError> {
    debug!("signup_handler enter");
    let r = User::verify(&input.email, &input.password, &state.pool).await?;
    match r {
        None => {
            Ok((StatusCode::FORBIDDEN, "invalid email or password").into_response())
        }
        Some(user) => {
            let token = state.ek.encode(user.clone())?;
            Ok((StatusCode::OK, Json(Token { token })).into_response())
            // Ok((StatusCode::FORBIDDEN, "invalid email or password".to_string()))
        }
    }
}